// ctx.save()；保存当前环境的状态，可以把当前绘制环境进行保存到缓存中
// ctx.restore()；返回之前保存过的路径状态和属性
// ctx.globalAlpha=number；设置绘制环境的透明度，值介于0-1之间
// ctx.clip()；在画布的限定区域绘制，从原始画布中剪切任意形状和尺寸，一旦剪切了某个区域，则所有之后的绘图都会被限制在被剪切的区域内
// canvas.toDataURL(type, encoderOptions)；把 canvas 绘制的内容输

//获取主域和开放数据域共享的 sharedCanvas。只有开放数据域能调用
const canvas = wx.getSharedCanvas();
/** @type { CanvasRenderingContext2D } */
const ctx = canvas.getContext('2d');
/**
 * 保存已经加载的图片
 */
const assets = new Map();
/**
 * 使用微信接口创建图片
 * @param {*} source 
 * @returns 
 */
function wxImage(source) {
    //创建一个图片对象
    const image = wx.createImage();
    //图片加载完成后触发的回调函数
    image.onload = render;
    //指定图片地址
    image.src = source;
    //已加载保存到map中
    assets.set(source, image);
    return image;
}
/**
 * 加载图片，如果已加载则直接返回，否则直接加载
 * @param {*} source 
 * @returns 
 */
function resLoader(source) {
    return assets.has(source) ? assets.get(source) : wxImage(source);
}
/**
 * 绘制图片基本方式，x y 为绘片左上角的坐标， img是绘制图
 * @param {*} source 
 * @param {*} x 
 * @param {*} y 
 */
function drawImage(source, x, y) {
    const image = resLoader(source);
    ctx.drawImage(image, x, y);
}
function drawImageByWH(source, x, y,width,height) {
  const image = resLoader(source);
  ctx.drawImage(image, x, y, width,height);
}
/**
 * 画头像
 * @param {*} source 图片地址
 * @param {*} x 横坐标
 * @param {*} y 纵坐标
 * @param {*} r 半径
 */
function drawAvatar(source, x, y, r) {
    ctx.save();
    ctx.beginPath();
    //绘制圆形 圆心到最右边点为 0 度，顺时针方向依次增大；eAngle 结束角度，注意用的是弧度 Π(180°)；counterclockwise：是否是逆时针，true 是逆时针，false 顺时针。
    ctx.arc(x + r, y + r, r, 0, 2 * Math.PI);
    ctx.clip();
    const image = resLoader(source);
    //绘制图片基本方式，x y 为绘片左上角的坐标， img是绘制图片 
    //绘制图片并规定宽高
    ctx.drawImage(image, x, y, r * 2, r * 2);
    ctx.restore();
}
/**
 * 画文字
 * @param {*} text 
 * @param {*} x 
 * @param {*} y 
 * @param {*} size 
 * @param {*} color 
 * @param {*} maxWidth 
 * @param {*} textAlign 
 */
function drawText(text, x, y, size, color, maxWidth, textAlign) {
    if (blnAndroid) {
        //console.log("安卓设置黑体");
        ctx.font = `bold ${size}px Heiti `;
    } else {
        //console.log("苹果设置PingFangSC")
        ctx.font = `bold ${size}px PingFangSC-Regular,sans-serif`;
    }
    ctx.fillStyle = '#' + color;
    ctx.textBaseline = 'top';
    ctx.textAlign = textAlign || 'left';
    //填充文本
    ctx.fillText(text, x, y);
}
/**
 * 画图片文字
 * @param {*} text 
 * @param {*} x 
 * @param {*} y 
 * @param {*} size 
 * @param {*} urlKey 
 * @param {*} textAlign 
 */
function drawTextImage(text, x, y, size, urlKey, textAlign) {
    var startX = x;
    var len = text.length;
    if (textAlign == 'right') {
        startX -= len * size
    }
    else if (textAlign == 'center') {
        startX -= len / 2 * size
    }
    for (let i = 0; i < len; i++) {
        const textStr = text[i];
        var str = `${urlKey}${textStr}.png`;
        //绘制图片基本方式，x y 为绘片左上角的坐标
        drawImage(str, startX + i * size, y);
    }

}

const utils = {
    byteLength(s) {
        let len = 0;
        for (let i = 0; i < s.length; i++) {
            len += s.charCodeAt(i) > 999 ? 2 : 1;
            if (s.codePointAt(i) > 0xffff) i++;
        }
        return len;
    },
    subByteLen(s, subLen) {
        let len = 0;
        let subStr = '';
        for (let i = 0; i < s.length; i++) {
            subStr += s[i];
            len += s.charCodeAt(i) > 999 ? 2 : 1;
            if (s.codePointAt(i) > 0xffff) {
                subStr += s[i + 1];
                i++;
            }
            if (len >= subLen) break;
        }
        return subStr;
    },
    subNickName(s) {
        return utils.byteLength(s) > 12 ? utils.subByteLen(s, 10) + '...' : s;
    },
    subNickNameByLen(s,len) {
      return utils.byteLength(s) > len ? utils.subByteLen(s, len) + '...' : s;
  },
};

/** @type {WechatMinigame.UserGameData[]} */
let users = [];
/** @type {WechatMinigame.UserInfo} */
let myself = null;
let offsetY = 0;
//是否是安卓
let blnAndroid = true;
//当前玩到分数
let curScore = 0;
//好友排行榜位置信息配置
//列表宽高
const area = {
    x: 0,
    y: 0,
    width: 868,//783,
    height: 920//480,
};
//每条列表项数据
const userUi = {
    x: 0,
    y: area.y,
    height: 110,
    marginTop: 1,
};
//我的
const myUi = {
    x: userUi.x,
    y: 930,//606,
};

//前3名排行榜位置信息配置
//前3名
const userUi3 = {
    x: 0,
    y: 0,
    width: 140,
    spX: 20,//间隔
};

/**渲染类型，1列表，2前3名 */
var randerType = 1;
function render() {
    //console.log("render渲染",randerType)
    switch (randerType) {
        case 1:
            render1();
            break;
        case 2:
            render2();
            break;
        case 3:
            renderExceed();
            break;
        case 4:
            renderFirst();
        break;
    }

}
/**列表 */
function render1() {
    //console.log("render1")
    //Canvas的API提供了两个名叫save()和restore()的方法，用于保存及恢复当前Canvas绘图环境的所有属性。其中save()可以保存当前状态，而restore()可以还原之前保存的状态。
    //方法把当前绘画状态的一份拷贝压入到一个保存图像状态的栈中。这里的绘画状态指坐标原点、变形时的变化矩阵（该矩阵是调用 rotate()、scale() 和 translate() 的结果）、以及图形上下文对象的当前属性值等内容。
    //用来保存Canvas的状态。save之后，可以调用Canvas的平移、放缩、旋转、错切、裁剪等操作。  
    ctx.save();
    //清除矩形，相当于橡皮擦，在该矩形范围内的图像都会被擦除
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    //开启新状态的绘图，前面的设置不会被覆盖；新状态可以继承之前状态的样式，但是在新状态中设置的样式就只能作用在新状态当中
    ctx.beginPath();
    ctx.rect(area.x, area.y, area.width, area.height);
    //在画布的限定区域绘制，从原始画布中剪切任意形状和尺寸，一旦剪切了某个区域，则所有之后的绘图都会被限制在被剪切的区域内
    ctx.clip();
    drawUsers();
    //从栈中弹出存储的图形状态并恢复 CanvasRenderingContext2D 对象的属性、剪切路径和变换矩阵的值
    //用来恢复Canvas之前保存的状态。防止save后对Canvas执行的操作对后续的绘制有影响
    //save和restore要配对使用（restore可以比save少，但不能多），如果restore调用次数比save多，会引发Error
    ctx.restore();
    drawMyself();
    ctx.restore();
}
/**前3名 */
function render2() {
    console.log("render2")
    ctx.save();
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    drawUsers3();
}
/**
 * 还差多少米超越上一个好友
 */
function renderExceed() {
    ctx.save();
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    drawExceedUser();
    ctx.restore();
}

function drawExceedUser() {
    //获取上一名到好友
    let preUser = null;
    for (let i = (users.length-1); i >= 0; i--) {
        //console.log("socre:",users[i].score," curScore:",curScore)
        if (parseInt(users[i].score) > curScore) {
            preUser = users[i];
            break;
        }
    }
    //console.log('上一名到好友')
    //console.log(preUser)
    if (preUser) {
        
          //头像背景
          drawImage(`openDataContext/assets/Head_Avatar.png`, 580, 303);
//头像
        drawAvatar(preUser.avatarUrl, 583, 307, 40);
        //昵称
        let text = `${utils.subNickNameByLen(preUser.nickname,8)}`;
        drawText(`还差`,  170, 330, 32, '000000');
        drawText(`${preUser.score-curScore}米`,  275, 330, 32, 'ff0000',null, 'center');
        drawText('超越',  325, 330, 32, '000000');
        drawText(text,  405, 330, 32, 'ff0000');
    }else{
        drawText(`加油，再来一次你就是榜一`,  170, 330, 32, 'ff0000');
    }

}

function renderFirst(){
  ctx.save();
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    drawFist();
    ctx.restore();
}

function drawFist(){
  //头像背景
  if(users.length > 0){
    drawImage(users[0].avatarUrl, 128, 396);
  }
  
}

/**
 * @param {WechatMinigame.UserGameData} user
 */
function drawUser(x, y, user, i, color0, blnMe) {
    //console.log("drawUser,",i)
    //color0 = '000000';
    //整体背景imgItemBg
    if (blnMe) {
        //自己
        drawImage(`openDataContext/assets/Mine_bod.png`, x, y);
    } else {
        switch (i) {
            case 0:
                drawImage(`openDataContext/assets/First_bod.png`, x, y);
                break;
            case 1:
                drawImage(`openDataContext/assets/Second_bod.png`, x, y);
                break;
            case 2:
                drawImage(`openDataContext/assets/Third_bod.png`, x, y);
                break;
            default:
                drawImage(`openDataContext/assets/Normal_bod.png`, x, y);
                break;
        }
    }


    // if (i < 3) {
    //   //前3名左侧背景
    //     drawImage(`openDataContext/assets/imgRankBg3.png`, x, y);
    // } else {
    //   //3名之后左侧背景
    //     drawImage(`openDataContext/assets/imgRankBg.png`, x, y);
    // }
    if (i < 3) {
        //前3名奖牌图
        drawImage(`openDataContext/assets/NO${i + 1}.png`, x + 33, y + 18);
    } else {
        //其它排名数字
        let x_offset = 58;
        if ((i + 1) < 10) {
            x_offset = 62;
        }
        //第4个参数25是分数2个数字之间的距离
        drawTextImage(`${i + 1}`, x + x_offset, y + 25, 26, `openDataContext/assets/rankIndex/rankIndex_`, 'center');
    }
    //头像背景
    drawImage(`openDataContext/assets/imgAvatarBg.png`, x + 204, y + 20);
    //头像
    drawAvatar(user.avatarUrl, x + 205, y + 21, 30);
    //昵称
    drawText(utils.subNickName(user.nickname), x + 290, y + 35, 32, color0);
    //分数
    const score = user.score;
    //第4个参数25是分数2个数字之间的距离
    drawTextImage(`${score}`, x + 700 + 20, y + 25, 25, `openDataContext/assets/score/score_`, 'right');
    //m
    drawText('m', x + 710 + 20, y + 32, 32, color0);
}

function drawUsers() {
    //console.log("drawUsers users.length=",users.length)
    users.forEach((user, i) => {
        const x = userUi.x;
        const y = userUi.y + (userUi.height + userUi.marginTop) * i + offsetY;
        if (y < userUi.y - (userUi.height + userUi.marginTop)) return;
        if (y > userUi.y + area.height) return;
        drawUser(x, y, user, i, 'ffffff', false);
    });
}

function drawMyself() {
    if (!myself) return;
    const i = users.findIndex(
        (user) => user.avatarUrl === myself.avatarUrl && user.nickname === myself.nickName
    );
    if (i === -1) return;
    const user = users[i];
    drawUser(myUi.x, myUi.y, user, i, 'ffffff', true);
}

/**
 * @param {WechatMinigame.UserGameData} user
 */
function drawUser3(x, y, user, i, isMy) {
    if (isMy) {
        drawImage(`openDataContext/assets/rank3/imgBgMy.png`, x, y);
        drawImage(`openDataContext/assets/rank3/imgScoreBgMy.png`, x + 31, y + 139);
    }
    else {
        drawImage(`openDataContext/assets/rank3/imgBg.png`, x, y);
        drawImage(`openDataContext/assets/rank3/imgScoreBg.png`, x + 31, y + 139);
    }
    if (i == 0) {
        drawImage(`openDataContext/assets/rank3/rank3Cap.png`, x + 73, y + 15);
    }
    drawImage(`openDataContext/assets/rank3/rankIndex${i + 1}.png`, x + 13, y + 14);
    drawImage(`openDataContext/assets/rank3/imgAvatarBg.png`, x + 37, y + 31);
    drawAvatar(user.avatarUrl, x + 40, y + 35, 30);

    drawText(utils.subNickName(user.nickname), x + 70, y + 105, 18, 'AB6A3D', undefined, 'center');
    const detail = user.detail;
    drawText(`${detail.score}`, x + 70, y + 144, 16, isMy ? '829b35' : 'AB6A3D', undefined, 'center');
}

function drawUsers3() {
    users = users.slice(0, 3)
    users.forEach((user, i) => {
        const x = userUi3.x + (userUi3.spX + userUi3.width) * i;
        const y = userUi3.y;
        drawUser3(x, y, user, i, user.avatarUrl === myself.avatarUrl && user.nickname === myself.nickName);
    });
}

function initPlantform() {
    wx.getSystemInfo({
        success: function (res) {
            //console.log("res.system=",res.system)
            if (res.system.indexOf('Android') > -1) {
                //console.log("是安卓")
                blnAndroid = true;
            } else {
                //console.log("是苹果")
                blnAndroid = false;
            }
        }
    })

}

function init() {
    offsetY = 0;
    render();
    var key = 'RankData';
    wx.getFriendCloudStorage({
        keyList: [key],
        success(res) {
            users.length = 0;
            //console.log("获取好友数据成功")
            //console.log(res.data)
            res.data.forEach((user) => {
                let itemData = user.KVDataList.find((item) => item.key === key)
                if (!itemData) return;
                //if(!itemData.value)return;
                // console.log("itemData")
                // console.log(itemData);
                // console.log("user:");
                // console.log(user)
                //const detail = itemData.value;//JSON.parse(itemData.value);
                const { avatarUrl, nickname } = user;
                users.push({
                    avatarUrl,
                    nickname,
                    score: itemData.value
                });
            });
            users.sort(
                (a, b) =>
                    b.score - a.score
            );

            //console.log("users.length=", users.length)
            render();
        },
        fail(res) {
            //console.log("获取好友失败")
            ctx.fillText('加载失败', 1028, 463);
        },
    });
    wx.getUserInfo({
        openIdList: ['selfOpenId'],
        success(res) {
            //console.log("获取自己的信息成功:")
            //console.log(res.data[0]);
            myself = res.data[0];
            render();
        },
        fail(res) {
            //console.log("获取自己的信息失败")
        }
    });
}

function updateMaxScore(score) {
    //console.log('在子域中先取分数，再判断是否要上传');
    wx.getUserCloudStorage(
        {
            keyList: ['RankData'],
            success: (res) => {
                //console.log('getUserCloudStorage success', res)
                if (res.KVDataList.length == 0) {
                    // 第一次直接上传
                    //console.log("第一次直接上传")
                    wx.setUserCloudStorage(
                        {
                            KVDataList: [{ key: 'RankData', value: `${score}` }],
                            success: (res) => {
                                //console.log("success", res);
                            },
                            fail: res => {
                                console.log("fail", res);
                            }
                        }
                    )
                } else {
                    //比较大小后再传
                    //console.log('自己的数据', res.KVDataList[0].value, " 新打的分数：", score);
                    if (score > parseInt(res.KVDataList[0].value)) {
                        //console.log("是新的高分，上传分数")
                        wx.setUserCloudStorage(
                            {
                                KVDataList: [{ key: 'RankData', value: `${score}` }],
                                success: (res) => {
                                    //console.log("success", res);
                                },
                                fail: res => {
                                    console.log("fail", res);
                                }
                            }
                        )
                    }
                }


            },
            fail: (res) => {
                console.log('getUserCloudStorage fail', res)
            }
        }
    )
}

function scroll(value) {
    if (!isScrollEnable) return;
    offsetY += value;
    offsetY = Math.max(
        offsetY,
        -(userUi.height + userUi.marginTop) * (users.length) + area.height - userUi.marginTop
    );
    offsetY = Math.min(offsetY, 0);
    render();
}

let isScrollEnable = false;
wx.onMessage((res) => {
    //console.log("onMessage", res);
    switch (res.type) {
        case 'intData':
            initPlantform();
            init();
            break;
        case 'render': {
            isScrollEnable = true;
            randerType = 1;
            init();
            break;
        }
        case 'render3': {
            isScrollEnable = false;
            randerType = 2;
            init();
            break;
        }
        case 'close': {
            isScrollEnable = false;
            break;
        }
        case 'getSelfUserInfo': {
            isScrollEnable = false;
            break;
        }
        case 'updateMaxScore': {
            curScore = res.value;
            randerType = 3;
            isScrollEnable = false;
            updateMaxScore(res.value);
            //render();
            break;
        }
        case 'exceed': {
          //结算界面超越好友
          randerType = 3;
            isScrollEnable = false;
            render();
            break;
        }
        case 'showFst': {
          //首页logo上面显示第一名头像
          randerType = 4;
          isScrollEnable = false;
          render();
          break;
        }
    }
});
//console.log("初始化开放域")
//init();

const systemInfo = wx.getSystemInfoSync();
const ratio = 1125 / systemInfo.screenWidth;

let lastTouch = 0;
let lastTime = 0;
let frameId = 0;
let rate = 0;
let stopId = 0;
wx.onTouchStart((e) => {
    //取消由 requestAnimationFrame 添加到计划中的动画帧请求
    cancelAnimationFrame(frameId);
    lastTouch = e.changedTouches[0].clientY;
    lastTime = Date.now();
});
wx.onTouchMove((e) => {
    const p = e.changedTouches[0].clientY;
    rate = p - lastTouch;
    scroll((p - lastTouch) * ratio);
    lastTouch = p;
    lastTime = Date.now();
});
wx.onTouchEnd((e) => {
    const p = e.changedTouches[0].clientY;
    if (Date.now() - lastTime < 50) startInertia(rate * ratio);
});

/**
 * @param {number} v
 */
function startInertia(v) {
    v *= 1.3;
    const go = () => {
        scroll(v);
        v -= (v / Math.abs(v)) * 0.3;
        if (Math.abs(v) > 3) {
            //在下次进行重绘时执行
            frameId = requestAnimationFrame(go);
        }
    };
    frameId = requestAnimationFrame(go);
}
